/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package devlight.io.library;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.global.resource.NotExistException;
import ohos.media.image.PixelMap;
import ohos.media.image.common.Size;

import java.io.IOException;

/**
 * 可滑动的imageView 实例代码
 *
 * @since 2021-07-13
 */
public class SlideComponent extends Component implements Component.DrawTask, Component.EstimateSizeListener {
    private int width;
    private int height;
    private float rate;
    private float originalRate;
    private PixelMap pixelMap;
    private float bitmapX;
    private float bitmapY;
    private int slideSize;
    private AttrSet attrSet;
    private Axis axis;
    private static final String sourceTag = "siv_source";
    private static final String rateTag = "siv_rate";
    private static final String axisTag = "siv_axis";
    private PixelMapElement pixelMapElement;
    private Paint paint;
    private EventHandler handler;
    private static final int invalidateMsg = 1;
    private boolean isHasSend = false;
    private EventRunner eventRunner = EventRunner.getMainEventRunner();
    private static final int delayTimeLong = 5;
    private static final int ratePix = -1;

    /**
     * Axis 定义横竖滑动模式
     *
     * @since 2021-07-16
     */
    public enum Axis {
        HORIZONTAL,
        VERTICAL
    }

    private HorizontalDirection horizontalDirection = HorizontalDirection.LEFT_TO_RIGHT;

    /**
     * HorizontalDirection 滑动左右方向定义
     *
     * @since 2021-07-16
     */
    private enum HorizontalDirection {
        LEFT_TO_RIGHT,
        RIGHT_TO_LEFT
    }

    private VerticalDirection verticalDirection = VerticalDirection.TOP_TO_BOTTOM;

    /**
     * 竖屏上下滑动方向
     *
     * @since 2021-07-16
     */
    private enum VerticalDirection {
        TOP_TO_BOTTOM,
        BOTTOM_TO_TOP
    }

    /**
     * SlideComponent 定义横竖滑动模式
     *
     * @param context 上下文
     * @param attrs 属性
     * @since 2021-07-16
     */
    public SlideComponent(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrs 属性值
     * @param defStyleAttr 样式
     * @since 2021-07-16
     */
    public SlideComponent(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.attrSet = attrs;
        paint = new Paint();
        handler = new MyHandler(eventRunner);
        addDrawTask(this);
        setEstimateSizeListener(this);
        Element sourceImage = attrSet.getAttr(sourceTag).get().getElement();
        pixelMapElement = (PixelMapElement) sourceImage;
        float mRate = attrSet.getAttr(rateTag).get().getFloatValue();
        setRate(mRate);
        String mAxis = attrSet.getAttr(axisTag).get().getStringValue();
        if ("horizontal".equals(mAxis)) {
            setAxis(Axis.HORIZONTAL);
        } else if ("vertical".equals(mAxis)) {
            setAxis(Axis.VERTICAL);
        } else {
            setAxis(Axis.HORIZONTAL);
        }
        setSource(pixelMapElement.getPixelMap());
    }

    /**
     * 设置滑动速率
     *
     * @param rate 滑动速率
     * @since 2021-07-16
     */
    public void setRate(float rate) {
        this.rate = rate * ratePix;
        this.originalRate = this.rate;
    }

    /**
     * 设置滑动规则
     *
     * @param axis 滑动规则
     * @since 2021-07-16
     */
    private void setAxis(Axis axis) {
        this.axis = axis;
        this.originalRate = this.rate;
    }

    /**
     * 设置滑动规则
     *
     * @param axis 滑动规则
     * @since 2021-07-16
     */
/*    private void setAxis(int axis) {
        if (axis == 0) {
            this.axis = Axis.HORIZONTAL;
        } else {
            this.axis = Axis.VERTICAL;
        }
    }*/

    /**
     * 根据resource id 设置滑动图片资源
     *
     * @param sourceId 滑动图片资源
     * @since 2021-07-16
     */
    public void setSource(int sourceId) {
        try {
            pixelMapElement = new PixelMapElement(getResourceManager().getResource(sourceId));
            pixelMap = pixelMapElement.getPixelMap();
        } catch (IOException | NotExistException e) {
            e.getMessage();
        }
    }

    /**
     * 设置滑动图片资源
     *
     * @param source 滑动图片资源
     * @since 2021-07-16
     */
    public void setSource(PixelMap source) {
        this.pixelMap = source;
    }

    /**
     * 初始化滑动图片参数
     *
     * @since 2021-07-16
     */
    private void createSource() {
        this.bitmapX = 0;
        this.bitmapY = 0;
        this.horizontalDirection = HorizontalDirection.LEFT_TO_RIGHT;
        this.verticalDirection = VerticalDirection.TOP_TO_BOTTOM;
        this.rate = this.originalRate;
        PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
        if (this.pixelMap != null) {
            if (this.axis == Axis.HORIZONTAL) {
                options.size = new Size(this.height * this.pixelMap.getImageInfo().size.width
                    / this.pixelMap.getImageInfo().size.height,
                    this.height);
                this.slideSize = (options.size.width - this.width) * ratePix;
            } else {
                Size size = new Size(this.width,
                    this.width * this.pixelMap.getImageInfo().size.height / this.pixelMap.getImageInfo().size.width);
                options.size = size;
                this.slideSize = options.size.height - this.height;
            }
        } else {
            options.size = new Size(width, height);
        }
        pixelMap = PixelMap.create(this.pixelMap, options);
    }

    /**
     * 重写绘画方法
     * @param component 组件
     * @param canvas 画布
     */
    @Override
    public void onDraw(Component component, Canvas canvas) {
        paint.setAntiAlias(true);
        paint.setStrokeWidth(1);
        paint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        paint.setStyle(Paint.Style.STROKE_STYLE);
        if (this.axis == Axis.HORIZONTAL) {
            if (this.horizontalDirection == HorizontalDirection.LEFT_TO_RIGHT) {
                if (bitmapX <= slideSize && Math.abs(Math.round(this.bitmapX) - this.slideSize) >= 0) {
                    this.rate = -this.rate;
                    this.horizontalDirection = HorizontalDirection.RIGHT_TO_LEFT;
                }
            } else {
                if (Math.round(this.bitmapX) == 0) {
                    this.rate = -this.rate;
                    this.horizontalDirection = HorizontalDirection.LEFT_TO_RIGHT;
                }
            }
            this.bitmapX += this.rate;
            this.bitmapY = 0;
        } else {
            if (this.verticalDirection == VerticalDirection.TOP_TO_BOTTOM) {
                if (bitmapY < slideSize && Math.abs(Math.round(this.bitmapY) - this.slideSize) >= 0) {
                    this.rate = -this.rate;
                    this.verticalDirection = VerticalDirection.BOTTOM_TO_TOP;
                }
            } else {
                if (Math.round(this.bitmapY) == 0) {
                    this.rate = -this.rate;
                    this.verticalDirection = VerticalDirection.TOP_TO_BOTTOM;
                }
            }

            this.bitmapX = 0;
            this.bitmapY += this.rate;
        }
        canvas.drawPixelMapHolder(new PixelMapHolder(pixelMap), this.bitmapX, this.bitmapY, paint);
        if (!isHasSend) {
            isHasSend = true;
            handler.sendEvent(invalidateMsg);
        }
        if (axis == Axis.VERTICAL && Math.abs(bitmapY) > pixelMap.getImageInfo().size.height) {
            handler.removeAllEvent();
            eventRunner.stop();
        }
        if (axis == Axis.HORIZONTAL && Math.abs(bitmapX) > pixelMap.getImageInfo().size.width) {
            handler.removeAllEvent();
            eventRunner.stop();
        }
    }

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        this.width = Component.EstimateSpec.getSize(widthEstimateConfig);
        this.height = Component.EstimateSpec.getSize(heightEstimateConfig);
        createSource();
        setEstimatedSize(Component.EstimateSpec.getChildSizeWithMode(width, width, EstimateSpec.NOT_EXCEED),
            Component.EstimateSpec.getChildSizeWithMode(height, height, EstimateSpec.NOT_EXCEED));
        return true;
    }

    /**
     * 自定义EventHandler
     *
     * @since 2021-07-16
     */
    private class MyHandler extends EventHandler {
        MyHandler(EventRunner runner) throws IllegalArgumentException {
            super(runner);
        }

        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            switch (event.eventId) {
                case invalidateMsg:
                    invalidate();
                    handler.sendEvent(invalidateMsg, delayTimeLong);
                    break;
                default:
                    break;
            }
        }
    }
}
